#include <ESP8266WiFi.h>        // 本程序使用 ESP8266WiFi库
#include <ESP8266WiFiMulti.h>   //  ESP8266WiFiMulti库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库
#include <ArduinoJson.h>

void connectWiFi();

ESP8266WiFiMulti wifiMulti;     // 建立ESP8266WiFiMulti对象,对象名称是 'wifiMulti'
ESP8266WebServer esp8266_server(80);// 建立网络服务器对象，该对象用于响应HTTP请求。监听端口（80）
const char* ssid = "";       //你的wifi名称
const char* password = "";       //你的密码

int flag = 0;
int ledTimeDelay = 0;

void setup(void){
  Serial.begin(9600);   // 启动串口通讯
 
  pinMode(LED_BUILTIN, OUTPUT); //设置内置LED引脚为输出模式以便控制LED
  connectWiFi();    // 连接wifi
 
                    
  esp8266_server.begin();                           // 启动网站服务
//  esp8266_server.on("/", HTTP_GET, handleRoot);     // 设置服务器根目录即'/'的函数'handleRoot'
  esp8266_server.on("/LedOn", HTTP_POST, handleLedOn);  // 设置处理LED控制请求的函数'handleLED'
  esp8266_server.on("/LedOff", HTTP_POST, handleLedOff);  // 设置处理LED控制请求的函数'handleLED'
  esp8266_server.on("/StreamLed", HTTP_POST, streamLed);  // 设置处理LED控制请求的函数'handleLED'
  esp8266_server.on("/LedDelayControl", HTTP_POST, handleLedDelayControl);  // 设置处理LED控制请求的函数'handleLED'
  esp8266_server.onNotFound(handleNotFound);        // 设置处理404情况的函数'handleNotFound'
 
  Serial.println("HTTP esp8266_server started");//  告知用户ESP8266网络服务功能已经启动
}
 
void loop(void){
  esp8266_server.handleClient();                     // 检查http服务器访问
  streamLedInLoop();
}
 

// 连接WiFi
void connectWiFi(){
  WiFi.begin(ssid, password);                  // 启动网络连接
  Serial.print("Connecting to ");              // 串口监视器输出网络连接信息
  Serial.print(ssid); Serial.println(" ...");  // 告知用户NodeMCU正在尝试WiFi连接
  
  int i = 0;                                   // 这一段程序语句用于检查WiFi是否连接成功
  while (WiFi.status() != WL_CONNECTED) {      // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。 
    delay(1000);                               // 如果WiFi连接成功则返回值为WL_CONNECTED                       
    Serial.print(i++); Serial.print(' ');      // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值
  }                                            // 同时NodeMCU将通过串口监视器输出连接时长读秒。
                                               // 这个读秒是通过变量i每隔一秒自加1来实现的。                                              
  Serial.println("");                          // WiFi连接成功后
  Serial.println("Connection established!");   // NodeMCU将通过串口监视器输出"连接成功"信息。
  Serial.print("IP address:    ");             // 同时还将输出NodeMCU的IP地址。这一功能是通过调用
  Serial.println(WiFi.localIP());              // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。  
}

void handleRoot() {      
  String str;
//  str =  "<form action=\"/LedOn\" method=\"POST\"><input type=\"submit\" value=\"Turn on LED\"></form>";
//  str += "<form action=\"/LedOff\" method=\"POST\"><input type=\"submit\" value=\"Turn off LED\"></form>";
//  str += "<form action=\"/StreamLed\" method=\"POST\"><input type=\"submit\" value=\"Stream Led\"></form>";
//  esp8266_server.send(200, "text/html", str);
}
 
//处理LED控制请求的函数'handleLED'
void handleLedOn() {
  Serial.println("开灯");    
  flag = 0;                     
  digitalWrite(LED_BUILTIN,0);// 改变LED的点亮或者熄灭状态
  esp8266_server.send(200);
}
void handleLedOff() { 
  Serial.println("关灯");     
  flag = 0;                         
  digitalWrite(LED_BUILTIN,1);// 改变LED的点亮或者熄灭状态
  esp8266_server.send(200);
}

void streamLed() {
  String str = esp8266_server.arg(0);

  const size_t capacity = JSON_OBJECT_SIZE(1) + 30;
  DynamicJsonDocument doc(capacity);
  deserializeJson(doc, str);
  flag = doc["isStreamLedOn"].as<int>();
  Serial.println("StreamLedStatus:" + String(flag));  
  esp8266_server.send(200);                 
}

void streamLedInLoop()
{
  
  if(flag==1){
      digitalWrite(LED_BUILTIN,LOW);
      delay(ledTimeDelay);
      digitalWrite(LED_BUILTIN,HIGH);
      delay(ledTimeDelay);
  }
}

void handleLedDelayControl()
{
   String str = esp8266_server.arg(0);
   //解析字符串
   const size_t capacity = JSON_OBJECT_SIZE(1) + 10;
   DynamicJsonDocument doc(capacity);
   deserializeJson(doc, str);
   ledTimeDelay = doc["speed"].as<int>();
   Serial.println("Speed:" + String(ledTimeDelay));
   esp8266_server.send(200);
}
// 设置处理404情况的函数'handleNotFound'
void handleNotFound(){
  esp8266_server.send(404, "text/plain", "404: Not found"); // 发送 HTTP 状态 404 (未找到页面) 并向浏览器发送文字 "404: Not found"
}
